package tarantula.reporter;

import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;

import tarantula.collector.ExecResults;
import tarantula.collector.TestDataCollector;
import tarantula.instrumenter.SourcePos;
import tarantula.util.FileUtils;
import tarantula.util.Globals;

public class BuggyStatementReporter {
	
	public final String trace_file_dir;
	public final TestDataCollector datacollector;
	
	//configuration options
	public static float suspiciousness = 0.0f;
	public static float confidence = 0.0f;
	public static int output_num = -1; //output all according to suspicious
	
	public BuggyStatementReporter(String trace_dir) {
		assert trace_dir != null;
		this.trace_file_dir = trace_dir;
		this.datacollector = new TestDataCollector(this.trace_file_dir);
	}
	
	public Map<SourcePos, ExecResults> outputRankedBuggyStatement() {
		Map<SourcePos, ExecResults> retSources = new LinkedHashMap<SourcePos, ExecResults>();
		//parse all data
		Map<SourcePos, ExecResults> testData = this.datacollector.collectTestDataInfo();
		//filter according to the user input method
		Map<SourcePos, ExecResults> filterResults = new LinkedHashMap<SourcePos, ExecResults>();
		for(SourcePos pos : testData.keySet()) {
			ExecResults results = testData.get(pos);
			float susp = results.computeSuspiciousness();
			float confid = results.computeConfidence();
			if(susp <= suspiciousness || confid <= confidence
					) {
				continue;
			}
			filterResults.put(pos, results);
		}
		//then ranked according to suspicious
		float[] all_suspicious = new float[filterResults.size()];
		int index = 0;
		for(SourcePos pos : filterResults.keySet()) {
			ExecResults results = filterResults.get(pos);
			float susp = results.computeSuspiciousness();
			all_suspicious[index++] = susp;
		}
		//ranked
		Arrays.sort(all_suspicious);
		
		int outputLength = all_suspicious.length;
		if(output_num > -1 && output_num < all_suspicious.length) {
			outputLength = output_num;
		}
		
		//start to find
		for(int i = outputLength - 1; i >=0; i--) {
			float suspicious = all_suspicious[i];
			SourcePos pos = null;
			for(SourcePos p : filterResults.keySet()) {
				if(filterResults.get(p).computeSuspiciousness() == suspicious) {
					pos = p;
					break;
				}
			}
			if(pos == null) {
				throw new RuntimeException("can not find exec results with suspicious: " + suspicious);
			}
			ExecResults results = filterResults.get(pos);
			retSources.put(pos, results);
			//must delete it
			filterResults.remove(pos);
		}
		
		return retSources;
	}
	
	public void dumpReport(Map<SourcePos, ExecResults> sources, String fileName) {
		StringBuilder sb = new StringBuilder();
		
		sb.append("====");
		sb.append(Globals.lineSep);
		sb.append("Suspicious: " + suspiciousness);
		sb.append(Globals.lineSep);
		sb.append("Confidence: " + confidence);
		sb.append(Globals.lineSep);
		sb.append("Output num: " + output_num);
		sb.append(Globals.lineSep);
		sb.append("====");
		sb.append(Globals.lineSep);
		
		int rankedNum = 1;
		for(SourcePos pos : sources.keySet()) {
			ExecResults results = sources.get(pos);
			sb.append((rankedNum++));
			sb.append(". ");
			sb.append(pos.toString());
			sb.append(Globals.lineSep);
			sb.append("      ");
			sb.append(results.toString());
			sb.append(Globals.lineSep);
		}
		
		if(fileName == null) {
			System.out.println(sb.toString());
		} else {
			FileUtils.writeToFileNoExp(sb.toString(), fileName);
		}
	}
}
